﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

using vJine.Lua;

namespace vJine.Lua.UT {
    public enum MyStatus {
        H,
        E,
        L,
        O
    }

    public class result_class {
        public string STRING { get; set; }
        public int INT { get; set; }
    }

    public class MyClass {
        public MyClass My { get; set; }

        public bool B { get; set; }
        public bool? b { get; set; }
        public byte[] B_ { get; set; }

        public double D { get; set; }
        public double d { get; set; }

        public Guid G { get; set; }
        public Guid? g { get; set; }
        public Guid[] G_ { get; set; }

        public string S { get; set; }
        public string s { get; set; }
        public string[] s_ { get; set; }

        public DateTime DT { get; set; }
        public DateTime? dt { get; set; }
        public DateTime[] DT_ { get; set; }

        public MyStatus E { get; set; }
        public MyStatus? e { get; set; }
        public MyStatus[] E_ { get; set; }

        public static void M(MyStatus E) {
            string msg = string.Format("result[anonymous]:{0}", E);
        }

        public void m(MyStatus E) {
            string msg = string.Format("result[anonymous]:{0}", E);
        }

        public static string SM(int a, string b) {
            return string.Format("SM:Result:a,{0};b,{1}", a, b);
        }

        public string IM(int a, string b) {
            return string.Format("IM:Result:a,{0};b,{1}", a, b);
        }

        public string show_properties() {
            return string.Format("Properties:b,{0};d,{1};s,{2}", this.B, this.D, this.s);
        }

        public result_class return_class_result(string msg) {
            return new result_class() { STRING = "Hello:" + msg, INT = 5 };
        }

        public static void test_luaContext() {
            //获取Lua版本
            string V = LuaContext.Version;

            //实例化LuaContext
            LuaContext luaContext = new LuaContext();

            luaContext.reg<MyClass>("MyClass");
            object[] O = luaContext.eval("return MyClass().return_class_result('+world').STRING");

            string vars_name = "vJine.Lua.Vars.bool";
            //设置与读取堆栈变量
            bool v_bool = true;
            luaContext.set(true);
            luaContext.get(out v_bool);
            Debug.Assert(v_bool == true);
            luaContext.set(false);
            luaContext.get(out v_bool);
            Debug.Assert(v_bool == false);
            //设置与读取全局变量
            luaContext.set(vars_name, true);
            luaContext.get(vars_name, out v_bool);
            Debug.Assert(v_bool == true);
            luaContext.set(vars_name, false);
            luaContext.get(vars_name, out v_bool);
            Debug.Assert(v_bool == false);


            vars_name = "vJine.Lua.Vars.sbyte";
            sbyte v_sbyte = 0;
            luaContext.set(sbyte.MaxValue);
            luaContext.get(out v_sbyte);
            Debug.Assert(v_sbyte == sbyte.MaxValue);
            luaContext.set(sbyte.MinValue);
            luaContext.get(out v_sbyte);
            Debug.Assert(v_sbyte == sbyte.MinValue);

            luaContext.set(vars_name, sbyte.MaxValue);
            luaContext.get(vars_name, out v_sbyte);
            Debug.Assert(v_sbyte == sbyte.MaxValue);
            luaContext.set(vars_name, sbyte.MinValue);
            luaContext.get(vars_name, out v_sbyte);
            Debug.Assert(v_sbyte == sbyte.MinValue);


            vars_name = "vJine.Lua.Vars.byte";
            byte v_byte = 0;
            luaContext.set(byte.MaxValue);
            luaContext.get(out v_byte);
            Debug.Assert(v_byte == byte.MaxValue);
            luaContext.set(byte.MinValue);
            luaContext.get(out v_byte);
            Debug.Assert(v_byte == byte.MinValue);

            luaContext.set(vars_name, byte.MaxValue);
            luaContext.get(vars_name, out v_byte);
            Debug.Assert(v_byte == byte.MaxValue);
            luaContext.set(vars_name, byte.MinValue);
            luaContext.get(vars_name, out v_byte);
            Debug.Assert(v_byte == byte.MinValue);


            vars_name = "vJine.Lua.Vars.short";
            short v_short = 0;
            luaContext.set(short.MaxValue);
            luaContext.get(out v_short);
            Debug.Assert(v_short == short.MaxValue);
            luaContext.set(short.MinValue);
            luaContext.get(out v_short);
            Debug.Assert(v_short == short.MinValue);

            luaContext.set(vars_name, short.MaxValue);
            luaContext.get(vars_name, out v_short);
            Debug.Assert(v_short == short.MaxValue);
            luaContext.set(vars_name, short.MinValue);
            luaContext.get(vars_name, out v_short);
            Debug.Assert(v_short == short.MinValue);


            vars_name = "vJine.Lua.Vars.ushort";
            ushort v_ushort = 0;
            luaContext.set(ushort.MaxValue);
            luaContext.get(out v_ushort);
            Debug.Assert(v_ushort == ushort.MaxValue);
            luaContext.set(ushort.MinValue);
            luaContext.get(out v_ushort);
            Debug.Assert(v_ushort == ushort.MinValue);

            luaContext.set(vars_name, ushort.MaxValue);
            luaContext.get(vars_name, out v_ushort);
            Debug.Assert(v_ushort == ushort.MaxValue);
            luaContext.set(vars_name, ushort.MinValue);
            luaContext.get(vars_name, out v_ushort);
            Debug.Assert(v_ushort == ushort.MinValue);


            vars_name = "vJine.Lua.Vars.int";
            int v_int = 0;
            luaContext.set(int.MaxValue);
            luaContext.get(out v_int);
            Debug.Assert(v_int == int.MaxValue);
            luaContext.set(int.MinValue);
            luaContext.get(out v_int);
            Debug.Assert(v_int == int.MinValue);

            luaContext.set(vars_name, int.MaxValue);
            luaContext.get(vars_name, out v_int);
            Debug.Assert(v_int == int.MaxValue);
            luaContext.set(vars_name, int.MinValue);
            luaContext.get(vars_name, out v_int);
            Debug.Assert(v_int == int.MinValue);


            vars_name = "vJine.Lua.Vars.uint";
            uint v_uint = 0;
            luaContext.set(uint.MaxValue);
            luaContext.get(out v_uint);
            Debug.Assert(v_uint == uint.MaxValue);
            luaContext.set(uint.MinValue);
            luaContext.get(out v_uint);
            Debug.Assert(v_uint == uint.MinValue);

            luaContext.set(vars_name, uint.MaxValue);
            luaContext.get(vars_name, out v_uint);
            Debug.Assert(v_uint == uint.MaxValue);
            luaContext.set(vars_name, uint.MinValue);
            luaContext.get(vars_name, out v_uint);
            Debug.Assert(v_uint == uint.MinValue);


            vars_name = "vJine.Lua.Vars.long";
            long v_long = 0;
            luaContext.set(long.MaxValue);
            //luaContext.get(out v_long);
            //Debug.Assert(v_long == long.MaxValue, "long.max"); //最大值不过
            luaContext.set(long.MinValue);
            luaContext.get(out v_long);
            Debug.Assert(v_long == long.MinValue);

            luaContext.set(vars_name, long.MaxValue);
            //luaContext.get(vars_name, out v_long);
            //Debug.Assert(v_long == long.MaxValue, "long.max"); //最大值不过
            luaContext.set(vars_name, long.MinValue);
            luaContext.get(vars_name, out v_long);
            Debug.Assert(v_long == long.MinValue);


            vars_name = "vJine.Lua.Vars.ulong";
            ulong v_ulong = 0;
            luaContext.set(ulong.MaxValue);
            //luaContext.get(out v_ulong);
            //Debug.Assert(v_ulong == ulong.MaxValue, "ulong.max"); //最大值不过
            luaContext.set(ulong.MinValue);
            luaContext.get(out v_ulong);
            Debug.Assert(v_ulong == ulong.MinValue);

            luaContext.set(vars_name, ulong.MaxValue);
            //luaContext.get(vars_name, out v_ulong);
            //Debug.Assert(v_ulong == ulong.MaxValue, "ulong.max"); //最大值不过
            luaContext.set(vars_name, ulong.MinValue);
            luaContext.get(vars_name, out v_ulong);
            Debug.Assert(v_ulong == ulong.MinValue);


            vars_name = "vJine.Lua.Vars.float";
            float v_float = 0;
            luaContext.set(float.MaxValue);
            luaContext.get(out v_float);
            Debug.Assert(v_float == float.MaxValue);
            luaContext.set(float.MinValue);
            luaContext.get(out v_float);
            Debug.Assert(v_float == float.MinValue);

            luaContext.set(vars_name, float.MaxValue);
            luaContext.get(vars_name, out v_float);
            Debug.Assert(v_float == float.MaxValue);
            luaContext.set(vars_name, float.MinValue);
            luaContext.get(vars_name, out v_float);
            Debug.Assert(v_float == float.MinValue);


            vars_name = "vJine.Lua.Vars.double";
            double v_double = 0;
            luaContext.set(double.MaxValue);
            luaContext.get(out v_double);
            Debug.Assert(v_double == double.MaxValue);
            luaContext.set(double.MinValue);
            luaContext.get(out v_double);
            Debug.Assert(v_double == double.MinValue);

            luaContext.set(vars_name, double.MaxValue);
            luaContext.get(vars_name, out v_double);
            Debug.Assert(v_double == double.MaxValue);
            luaContext.set(vars_name, double.MinValue);
            luaContext.get(vars_name, out v_double);
            Debug.Assert(v_double == double.MinValue);

            string myTable = "vJine.Lua.Vars.MyTable";
            MyClass x1 =
                new MyClass() {
                    B = true, b = false, B_ = new byte[] { 1, 2, 3 }, D = 123.456, 
                    S = "vJine.Lua是Lua语言的C#封装库，可实现通过C#直接运行Lua脚本并与Lua脚本交互的功能。",
                    G = Guid.NewGuid(), DT = DateTime.Now, E = MyStatus.L, E_ = new MyStatus[] { MyStatus.E, MyStatus.O },
                    My = new MyClass() { s = "xVx", B = true, D = 9.99, G = Guid.NewGuid(), e = MyStatus.O, My = new MyClass() { } }
                };
            luaContext.set<MyClass>(myTable, x1);

            MyClass x2 = luaContext.get<MyClass>(myTable);
            {
                Debug.Assert(x1.B == x2.B);
                Debug.Assert(x1.D == x2.D);
                Debug.Assert(x1.s == x2.s);
            }

            luaContext.print_var("vJine.Lua.Vars");

            //注册:匿名方法
            luaContext.reg("vJine.Lua.funcs.anony", new Action<MyStatus>((MyStatus E) => {
                string msg = string.Format("result[anonymous]:{0}", E);
            }));
            //注册：静态方法
            luaContext.reg("vJine.Lua.funcs.M", new Action<MyStatus>(MyClass.M));
            //注册：实例方法
            luaContext.reg("vJine.Lua.funcs.m", new Action<MyStatus>(x1.m));

            //注册类：默认名称
            luaContext.reg<MyClass>();
            //注册类：自定义名称
            luaContext.reg<MyClass>("vJine.Lua.YourClass");

            //注入脚本:
            object[] R = luaContext.eval(
                "function callback(my_arg, ppp) return my_arg .. ' on_the_fly', ppp, 'kakahaha', 123, true end return true, 1.234, callback('vJine.Lua','papapa')");

            //调用脚本方法
            object[] Obj = luaContext.exec("callback", "vJine.Lua");
            luaContext.set("n_vJine.Lua");
            luaContext.set("n_papapa");
            Obj = luaContext.nexec("callback", 2);

            //加载脚本:
            luaContext.load("d:/vJine.Lua/start.lua", "vars.n1", "vars.n2", "vars.b3", "vars.s4");
            luaContext.print_var("vars");

            Obj =
                luaContext.exec("dotnet_args", 1, 1.2, true, "Hello#lua_args");

            luaContext.exec("show_table", "myTable");

            //打印变量:
            luaContext.print_var("vJine.Lua.UT.MyClass");
            luaContext.print_var("vJine.Lua.YourClass");
            luaContext.print_var("X");

            bool isNull = luaContext.is_null("MY.NULL");
            Debug.Assert(isNull == true);
            isNull = luaContext.is_null(myTable);
            Debug.Assert(isNull == false);

            //X
            luaContext.set("vJine.Lua.Vars.BOOL", true);
            Debug.Assert(luaContext.is_bool("vJine.Lua.Vars.BOOL"));

            //回收垃圾：
            luaContext.gc();

            luaContext.set("a.1", false);
            luaContext.print_var("a");
            bool xbool = true;
            luaContext.get("a.1", out xbool);
            bool isxbool = luaContext.is_bool("a.2");
            object[]RR = luaContext.eval("return a[1]");
        }
    }

    class Program {
        static void Main(string[] args) {
            try {
                MyClass.test_luaContext();
            } catch (Exception ex) {
                string msg = ex.Message;
            }
        }

    }
}
